using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace MIMPGameLibrary
{
    [Serializable]
    public class ControlPoint
    {
        private int cpID;
        /// <summary>
        /// The number used to uniquely identify this Control Point.
        /// </summary>
        public int ControlPointNumber {
            get { return cpID; }
            set { cpID = value; }
        }
        private Player controller;
        /// <summary>
        /// The Player who controls this Control Point.
        /// </summary>
        public Player Controller {
            get { return controller; }
            set { controller = value; }
        }
        private int strength;
        /// <summary>
        /// The strength with which the Controller controls this Control Point. If set to 0, also sets this.Controller to null.
        /// </summary>
        public int ControlStrength {
            get { return strength; }
            set {
                strength = Math.Min(value, maxStrength);
                if (strength == 0) {
                    controller = null;
                }
            }
        }
        private int maxStrength;
        /// <summary>
        /// The maximum control strength for this Control Point.
        /// </summary>
        public int MaxStrength {
            get { return maxStrength; }
            set { maxStrength = value; }
        }
        /// <summary>
        /// Creates a new Control Point.
        /// </summary>
        /// <param name="number">The number used to identify this Control Point.</param>
        /// <param name="maxStrength">The maximum strength with which this Control Point can be controlled.</param>
        /// <param name="controller">The Player who initially controls this Control Point (use null for no initial controller)</param>
        public ControlPoint(int number, int maxStrength, Player controller) {
            this.cpID = number;
            this.maxStrength = maxStrength;
            this.controller = controller;
            this.strength = 0;
        }
    }
    [Serializable]
    public class Hex
    {
        /// <summary>
        /// Enumerates the six directions (N,NE,SE,S,SW,NW) which describe the relationship between two Hexes.
        /// </summary>
        public enum Direction { N, NE, SE, S, SW, NW };

        public enum TerrainType { Field, Forest, Grass, Hills, Mountain, Swamp, Tundra, Water }

        private int row;
        /// <summary>
        /// Gets or sets the Hex's row.
        /// </summary>
        public int Row {
            get { return row; }
            set { row = value; }
        }
        private int col;
        /// <summary>
        /// Gets or sets the Hex's column.
        /// </summary>
        public int Col {
            get { return col; }
            set { col = value; }
        }
        private TerrainType terrain;
        /// <summary>
        /// Gets or sets the string that describes the terrain type of the Hex.
        /// </summary>
        public TerrainType Terrain {
            get { return terrain; }
            set { terrain = value; }
        }
        private Monster monsterOn;
        /// <summary>
        /// Gets or sets the refernce to the Monster on this hex. Null = no Monster on.
        /// </summary>
        public Monster MonsterOn {
            get { return monsterOn; }
            set { monsterOn = value; }
        }
        /// <summary>
        /// True if there is a Monster on the Hex, false otherwise.
        /// </summary>
        public bool IsMonsterOn {
            get { return monsterOn != null; }
        }
        private SortedList<Direction, Hex> neighbors;
        /// <summary>
        /// A List of all Hexes that border this one.
        /// </summary>
        public List<Hex> Neighbors {
            get { return new List<Hex>(neighbors.Values); }
        }
        /// <summary>
        /// The Hex that is this Hex's neighbor to the north.
        /// </summary>
        public Hex North {
            get { return neighbors[Direction.N]; }
        }
        /// <summary>
        /// The Hex that is this Hex's neighbor to the northeast.
        /// </summary>
        public Hex Northeast {
            get { return neighbors[Direction.NE]; }
        }
        /// <summary>
        /// The Hex that is this Hex's neighbor to the southeast.
        /// </summary>
        public Hex Southeast {
            get { return neighbors[Direction.SE]; }
        }
        /// <summary>
        /// The Hex that is this Hex's neighbor to the south.
        /// </summary>
        public Hex South {
            get { return neighbors[Direction.S]; }
        }
        /// <summary>
        /// The Hex that is this Hex's neighbor to the southwest.
        /// </summary>
        public Hex Southwest {
            get { return neighbors[Direction.SW]; }
        }
        /// <summary>
        /// The Hex that is this Hex's neighbor to the northwest.
        /// </summary>
        public Hex Northwest {
            get { return neighbors[Direction.NW]; }
        }
        private ControlPoint cp;
        /// <summary>
        /// The Control Point associated with this Hex, if there is one.
        /// </summary>
        public ControlPoint ControlPoint {
            get { return cp; }
            set { cp = value; }
        }
        /// <summary>
        /// True if this Hex has a Control Point, false otherwise.
        /// </summary>
        public bool HasControlPoint {
            get { return cp != null; }
        }

        /// <summary>
        /// Creates a new Hex object at row 0, column 0.
        /// </summary>
        public Hex() : this(0, 0, TerrainType.Grass) { }
        /// <summary>
        /// Creates a new Hex object with specified row and column.
        /// </summary>
        /// <param name="row">The row number of this Hex.</param>
        /// <param name="col">The column number of this Hex.</param>
        public Hex(int row, int col) : this(row, col, TerrainType.Grass) { }
        /// <summary>
        /// Creates a new Hex object with specified row and column.
        /// </summary>
        /// <param name="row">The row number of this Hex.</param>
        /// <param name="col">The column number of this Hex.</param>
        /// <param name="terrain">This Hex's terrain type.</param>
        public Hex(int row, int col, TerrainType terrain) {
            this.row = row;
            this.col = col;
            this.terrain = terrain;
            this.cp = null;
            neighbors = new SortedList<Direction, Hex>(6);
            neighbors.Add(Direction.N, null);
            neighbors.Add(Direction.NE, null);
            neighbors.Add(Direction.SE, null);
            neighbors.Add(Direction.S, null);
            neighbors.Add(Direction.SW, null);
            neighbors.Add(Direction.NW, null);
        }
        /// <summary>
        /// Returns the String representation of the Hex, which looks like "(x,y)[TerrainType]" 
        /// </summary>
        /// <returns></returns>
        public override string ToString() {
            return "(" + row + "," + col + ")[" + Enum.GetName(typeof(Hex.TerrainType), terrain) + "]";
        }
        /// <summary>
        /// Returns a String that represents both the Hex and the Control Point on the Hex, if there is one.
        /// </summary>
        /// <returns></returns>
        public string ToLongString() {
            string text = this.ToString();
            if (this.HasControlPoint) {
                if (cp.Controller != null) {
                    text += "\nControl point #" + cp.ControlPointNumber +
                        "\nControlled by : " + cp.Controller +
                        "\nControl strength: " + cp.ControlStrength + "/" + cp.MaxStrength;
                } else {
                    text += "\nControl point #" + cp.ControlPointNumber +
                        "\nControlled by: no one";
                }
            }
            return text;
        }
        /// <summary>
        /// Sets the neighboring Hex in the given Direction to the given Hex.
        /// </summary>
        /// <param name="dir">The Direction of the neighbor relative to this Hex.</param>
        /// <param name="neighbor">The Hex to set as the neighbor.</param>
        public void SetNeighbor(Direction dir, Hex neighbor) {
            if (neighbors[dir] != null) {
                throw new ArgumentException("The " + dir + " neighbor has already been set.");
            }
            neighbors[dir] = neighbor;
        }
        /// <summary>
        /// True if the given Hex is one of this Hex's neighbors, false otherwise.
        /// </summary>
        /// <param name="hex">The Hex to search this Hex's neighbors for.</param>
        /// <returns></returns>
        public bool IsNeighbor(Hex hex) {
            return neighbors.ContainsValue(hex);
        }
    }
}
